﻿Imports System.Net.Sockets 'contiene objetos para utilizar sockets
Imports System.Threading ' hilos de ejecucion proceso
Imports System.Text ' manejo de textos
'Imports System.IO

Public Class Servidor


    Private Structure DatosClientes
        Public SocketConexion As Socket ' socket para mantener la conexion del cliente
        Public Thread As Thread ' hilo para mantener conexion con el cliente
        Public UltimosDatos As String
    End Structure

    Private _tcpListener As TcpListener ' escucha conexiones con los clientes
    Private ReadOnly _clientes As New Hashtable() 'datos de los clientes conectados
    Private _tcpThread As Thread ' hilo tcp
    Private _idClienteActual As Net.IPEndPoint 'ip y puerto del ultimo cliente conectado
    Private _puerto As String

    Public Event NewConnection(ByVal idTerminal As Net.IPEndPoint)
    Public Event DatosRecibidos(ByVal idTerminal As Net.IPEndPoint)
    Public Event ConexionTerminada(ByVal idTerminal As Net.IPEndPoint)

    'Private tcpCliente As TcpClient

    'Private mensajesEnviarRecibir As Stream


    Public Property Ip As String
    'Public Sub Conectar()

    '    'Conexión con el servidor
    '    tcpCliente = New TcpClient
    '    tcpCliente.Connect(Ip, Puerto)
    '    'tcpThread = New Thread(AddressOf LeerSocket)
    '    'tcpThread.Start()

    'End Sub


    Public Property Puerto As Integer
        Get
            Return CInt(_puerto)
        End Get
        Set(ByVal value As Integer)
            _puerto = CStr(value)
        End Set
    End Property
    ''' <summary>
    ''' Procedimiento para establecer el servidor en modo escucha
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub StartListener()
        'tcpListener = New TcpListener(Net.Dns.GetHostEntry("localhost").AddressList(0), Puerto)

        If String.IsNullOrEmpty(Ip) Then
            _tcpListener = New TcpListener(Net.IPAddress.Loopback, Puerto)
        Else

            _tcpListener = New TcpListener(Net.IPAddress.Parse(Ip), Puerto)
        End If
        Try
            _tcpListener.Start()
            _tcpThread = New Thread(AddressOf EsperarConexion)
            _tcpThread.Start()
        Catch ex As Exception
            Exit Sub
        End Try

    End Sub
    ''' <summary>
    ''' Procedimiento para detener la escucha del servidor
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub StopListener()
        CerrarTodosClientes()
        Try
            _tcpThread.Abort()
        Catch ex As Exception

        End Try

        _tcpListener.Stop()
    End Sub
    ''' <summary>
    ''' Obtener informacion de cliente
    ''' </summary>
    ''' <param name="idCliente"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Public Function Obtener_datos(ByVal idCliente As Net.IPEndPoint) As String
        Dim infoCliente As DatosClientes
        infoCliente = _clientes(IdCliente)
        Obtener_datos = infoCliente.UltimosDatos
    End Function
    ''' <summary>
    ''' Cerrar la conexion del cliente
    ''' </summary>
    ''' <param name="idCliente"></param>
    ''' <remarks></remarks>
    Private Sub CerrarConexionCliente(ByVal idCliente As Net.IPEndPoint)
        Dim infoClienteActual As DatosClientes
        infoClienteActual = _clientes(IdCliente)
        infoClienteActual.SocketConexion.Close()
    End Sub
    ''' <summary>
    ''' Cerrar conexion con todos los clientes
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub CerrarTodosClientes()
        Dim infoCliente As DatosClientes

        For Each infoCliente In _clientes.Values
            Call cerrarConexionCliente(infoCliente.SocketConexion.RemoteEndPoint)
        Next

    End Sub
    ''' <summary>
    ''' Envio mensaje a un cliente
    ''' </summary>
    ''' <param name="idCliente"></param>
    ''' <param name="datos"></param>
    ''' <remarks></remarks>
    Private Sub EnviarMensaje(ByVal idCliente As Net.IPEndPoint, ByVal datos As String)
        Dim cliente As DatosClientes
        'obtener informacion cliente 
        cliente = _clientes(idCliente)
        'envio de mensaje o comando
        cliente.SocketConexion.Send(Encoding.ASCII.GetBytes(Datos))

    End Sub
    ''' <summary>
    ''' Enviar mensaje a todos
    ''' </summary>
    ''' <param name="datos"></param>
    ''' <remarks></remarks>
    Public Sub EnviaMensajeTodos(ByVal datos As String)
        Dim cliente As DatosClientes
        For Each cliente In _clientes.Values
            EnviarMensaje(cliente.SocketConexion.RemoteEndPoint, Datos)
        Next

    End Sub
    ''' <summary>
    ''' esperando conexion server
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub EsperarConexion()
        Dim datosClientes As DatosClientes

        While True
            'Guardamos información del cliente
            datosClientes.SocketConexion = _tcpListener.AcceptSocket
            _idClienteActual = datosClientes.SocketConexion.RemoteEndPoint
            datosClientes.Thread = New Thread(AddressOf LeerSocket)
            'agregar info al array
            SyncLock Me
                _clientes.Add(_idClienteActual, datosClientes)
            End SyncLock
            'generat evento nuevaconexion
            RaiseEvent NewConnection(_idClienteActual)

            'iniciar hilo
            datosClientes.Thread.Start()
        End While
    End Sub
    ''' <summary>
    ''' leer desde el socket
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub LeerSocket()
        Dim idReal As Net.IPEndPoint 'id cliente a asociar
        Dim recibir() As Byte
        Dim infoCliente As DatosClientes
        Dim ret As Integer = 0

        idReal = _idClienteActual
        infoCliente = _clientes(idReal)
        While True
            If infoCliente.SocketConexion.Connected Then
                recibir = New Byte(100) {}
                Try
                    ret = infoCliente.SocketConexion.Receive(recibir, recibir.Length, SocketFlags.None)
                    If ret > 0 Then
                        'guardar mensaje recibido
                        infoCliente.UltimosDatos = Encoding.ASCII.GetString(recibir)
                        _clientes(idReal) = infoCliente
                        RaiseEvent DatosRecibidos(idReal)

                    Else
                        RaiseEvent ConexionTerminada(idReal)
                        Exit While
                    End If
                Catch ex As Exception
                    If Not infoCliente.SocketConexion.Connected Then
                        RaiseEvent ConexionTerminada(idReal)
                        Exit While

                    End If
                End Try
            End If
        End While
        Call CerrarThreat(idReal)
    End Sub
    ''' <summary>
    ''' Cerrar hilo
    ''' </summary>
    ''' <param name="IdCliente"></param>
    ''' <remarks></remarks>
    Private Sub CerrarThreat(ByVal IdCliente As Net.IPEndPoint)
        Dim infoCliente As DatosClientes

        infoCliente = _clientes(IdCliente)
        Try
            infoCliente.Thread.Abort()
        Catch ex As Exception
            SyncLock Me
                _clientes.Remove(IdCliente)
            End SyncLock

        End Try
    End Sub
    'Private Sub LeerSocket(ByVal esCliente As Boolean)
    '    Dim BufferDeLectura() As Byte

    '    While True
    '        Try
    '            BufferDeLectura = New Byte(100) {}

    '            'Esperar a que llegue algún mensaje
    '            mensajesEnviarRecibir.Read(BufferDeLectura,
    '                  0, BufferDeLectura.Length)

    '            'Generar evento DatosRecibidos cuando se recibien datos desde el servidor
    '            RaiseEvent DatosRecibidos(Encoding.ASCII.GetString(BufferDeLectura))
    '        Catch e As Exception
    '            Exit While
    '        End Try
    '    End While

    '    'Finalizar conexión y generar evento ConexionTerminada
    '    RaiseEvent ConexionTerminada()
    'End Sub
    'Public Sub EnviarDatos(ByVal Datos As String)
    '    Dim BufferDeEscritura() As Byte

    '    BufferDeEscritura = Encoding.ASCII.GetBytes(Datos)
    '    If Not (mensajesEnviarRecibir Is Nothing) Then
    '        mensajesEnviarRecibir.Write(BufferDeEscritura,
    '                0, BufferDeEscritura.Length)
    '    End If
    'End Sub
End Class
